home *** CD-ROM | disk | FTP | other *** search
- Subject: v21i085: File distribution alternative to rdist, Part02/03
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 975c0789 2935d6ec 78d09f97 9606663f
-
- Submitted-by: Rich Salz <rsalz@bbn.com>
- Posting-number: Volume 21, Issue 85
- Archive-name: coda/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 2 (of 3)."
- # Contents: adt.c codaserver.8 file.c libvms.c server.c server.h
- # Wrapped by rsalz@litchi.bbn.com on Mon Apr 9 16:49:04 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'adt.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'adt.c'\"
- else
- echo shar: Extracting \"'adt.c'\" \(6748 characters\)
- sed "s/^X//" >'adt.c' <<'END_OF_FILE'
- X/*
- X** Copyright 1989 BBN Systems and Technologies Corporation.
- X** All Rights Reserved.
- X** This is free software, and may be distributed under the terms of the
- X** GNU Public License; see the file COPYING for more details.
- X**
- X** Data abstractions for CODA server.
- X*/
- X#include "server.h"
- X#include <sys/stat.h>
- X#ifdef RCSID
- Xstatic char RCS[] =
- X "$Header: adt.c,v 2.0 90/03/23 14:40:58 rsalz Exp $";
- X#endif /* RCSID */
- X
- X
- X/*
- X** A class maps a name to a list of strings. It's like a recursive
- X** definition of a collection. We keep a linked list of all our maps.
- X*/
- Xtypedef struct _CLASS {
- X struct _CLASS *Next; /* Next one */
- X char *Name; /* The name */
- X int NumHosts; /* Number of hosts in the class */
- X int MaxHosts; /* Amount of space allocated */
- X char **Hosts; /* List of hosts */
- X int NumClasses; /* Number of classes */
- X int MaxClasses; /* Amount of space allocated */
- X char **Classes; /* List of classes in the class */
- X} CLASS;
- X
- X
- XSTATIC CLASS BaseClass; /* Our linked list of classes */
- XSTATIC STRLIST BaseHost; /* List of hosts in Codafile */
- XSTATIC int MaxItem; /* Size of "Item" array */
- X
- X
- X
- X/*
- X** Remove all defined blocks, classes, and hosts. This is not likely to
- X** be called too often, so just flush memory -- the Add...() routines
- X** share pointers so a free'ing would be a bit of work. We use shared
- X** pointers not to save space, but to make string compares fast.
- X*/
- Xvoid
- XResetStorage()
- X{
- X BaseBlock.Next = NULL;
- X BaseClass.Next = NULL;
- X BaseHost.Next = NULL;
- X ResetItem();
- X}
- X
- X
- Xvoid
- XResetItem()
- X{
- X register ITEM *I;
- X register ITEM *Iend;
- X
- X NumItem = 0;
- X if (BaseItem == NULL) {
- X /* Since we can't trust realloc(NULL, ...) yet... */
- X MaxItem = ITEM_DELTA;
- X BaseItem = NEW(ITEM, MaxItem);
- X }
- X else
- X /* Free old strings. */
- X for (I = BaseItem, Iend = &BaseItem[NumItem]; I < Iend; I++)
- X free(I->Name);
- X}
- X
- X
- X
- X/*
- X** Guarantee an instantiation of a class.
- X*/
- XSTATIC CLASS *
- XFindOrCreateClass(Name)
- X register char *Name;
- X{
- X register CLASS *C;
- X
- X /* Rummage through the list. */
- X for (C = BaseClass.Next; C; C = C->Next)
- X if (EQ(C->Name, Name))
- X return C;
- X
- X /* Create a new class, add it to the list. */
- X C = NEW(CLASS, 1);
- X C->Next = BaseClass.Next;
- X C->Name = Name;
- X C->NumHosts = 0;
- X C->MaxHosts = HOST_DELTA;
- X C->Hosts = NEW(char*, C->MaxHosts);
- X C->NumClasses = 0;
- X C->MaxClasses = CLASS_DELTA;
- X C->Classes = NEW(char*, C->MaxClasses);
- X BaseClass.Next = C;
- X return C;
- X}
- X
- X
- X/*
- X** Add a host to a class.
- X*/
- Xvoid
- XAddHostToClass(Name, Host)
- X register char *Name;
- X register char *Host;
- X{
- X register char **str;
- X register CLASS *C;
- X register int i;
- X
- X C = FindOrCreateClass(Name);
- X
- X /* Look through list of hosts, see if it's already there. */
- X for (i = C->NumHosts, str = C->Hosts; --i >= 0; str++)
- X if (EQ(Host, *str))
- X return;
- X
- X /* Have to add it; do we need more room? */
- X if (C->NumHosts == C->MaxHosts - 1) {
- X C->MaxHosts += HOST_DELTA;
- X C->Hosts = GROW(C->Hosts, char*, C->MaxHosts);
- X }
- X
- X /* Add it. */
- X C->Hosts[C->NumHosts++] = Host;
- X}
- X
- X
- X/*
- X** Add a class to a class.
- X*/
- XSTATIC void
- XAddClassToClass(C, Name)
- X register CLASS *C;
- X register char *Name;
- X{
- X register char **str;
- X register int i;
- X
- X /* Look through list of classes, see if it's already there. */
- X for (i = C->NumClasses, str = C->Classes; --i >= 0; str++)
- X if (EQ(Name, *str))
- X return;
- X
- X /* Have to add it; do we need more room? */
- X if (C->NumClasses == C->MaxClasses - 1) {
- X C->MaxClasses += CLASS_DELTA;
- X C->Classes = GROW(C->Classes, char*, C->MaxClasses);
- X }
- X
- X /* Add it. */
- X C->Classes[C->NumClasses++] = Name;
- X}
- X
- X
- X
- X/*
- X** Add a list of classes to a class.
- X*/
- Xvoid
- XAddClassesToClass(Name, L)
- X register char *Name;
- X register STRLIST *L;
- X{
- X register CLASS *C;
- X
- X for (C = FindOrCreateClass(Name); L; L = L->Next)
- X AddClassToClass(C, L->Value);
- X}
- X
- X
- X
- X/*
- X** Return TRUE if the host is a member of the specified class.
- X*/
- Xint
- XHostIsInClass(Host, Class)
- X register char *Host;
- X register char *Class;
- X{
- X static char Everyone[] = ALL;
- X register char **str;
- X register CLASS *C;
- X register int i;
- X
- X /* Almost everyone is in the built-in class. */
- X if (EQ(Class, Everyone))
- X return !EQ(Host, UnknownHost) && HostWasDeclared(Host);
- X
- X /* Nobody is in undefined classes. */
- X for (C = BaseClass.Next; C; C = C->Next)
- X if (EQ(C->Name, Class))
- X break;
- X if (C == NULL)
- X return FALSE;
- X
- X /* Look through list of hosts, see if it's already there. */
- X for (i = C->NumHosts, str = C->Hosts; --i >= 0; str++)
- X if (EQ(Host, *str))
- X return TRUE;
- X
- X /* Recursively look through list of classes. */
- X for (i = C->NumClasses, str = C->Classes; --i >= 0; str++)
- X if (HostIsInClass(Host, *str))
- X return TRUE;
- X
- X /* Not there. */
- X return FALSE;
- X}
- X
- X
- X/*
- X** Look through the list of hosts, see if we've got that one.
- X*/
- Xint
- XHostWasDeclared(Name)
- X register char *Name;
- X{
- X register STRLIST *S;
- X
- X /* Rummage through the list. */
- X for (S = BaseHost.Next; S; S = S->Next)
- X if (EQ(S->Value, Name))
- X return TRUE;
- X
- X return FALSE;
- X}
- X
- X
- X/*
- X** Add a host to our list of known hosts.
- X*/
- Xvoid
- XDefineHost(Host, Class)
- X char *Host;
- X char *Class;
- X{
- X STRLIST *S;
- X
- X S = NEW(STRLIST, 1);
- X S->Value = Host;
- X S->Next = BaseHost.Next;
- X BaseHost.Next = S;
- X AddHostToClass(Class, Host);
- X}
- X
- X
- X
- X/*
- X** Look through the list of blocks, see if we've got that one.
- X*/
- XBLOCK *
- XFindBlock(Name)
- X register char *Name;
- X{
- X register BLOCK *B;
- X
- X /* Rummage through the list. */
- X for (B = BaseBlock.Next; B; B = B->Next)
- X if (EQ(B->Name, Name))
- X return B;
- X return NULL;
- X}
- X
- X
- X
- X/*
- X** Add to the list of things sent.
- X*/
- Xvoid
- XAddItemToList(Name, Sb)
- X char *Name;
- X struct stat *Sb;
- X{
- X ITEM *I;
- X
- X /* Need more room? */
- X if (NumItem == MaxItem - 1) {
- X MaxItem += ITEM_DELTA;
- X BaseItem = GROW(BaseItem, ITEM, MaxItem);
- X }
- X
- X I = &BaseItem[NumItem++];
- X I->Name = COPY(Name);
- X I->Uid = Sb->st_uid;
- X I->Gid = Sb->st_gid;
- X I->Directory= (Sb->st_mode & S_IFMT) == S_IFDIR;
- X I->Size = Sb->st_size;
- X I->Time = Sb->st_mtime;
- X I->Mode = Sb->st_mode & 0777;
- X}
- X
- X
- XSTATIC int
- XItemCompare(I1, I2)
- X ITEM *I1;
- X ITEM *I2;
- X{
- X return strcmp(I1->Name, I2->Name);
- X}
- X
- X
- X/*
- X** Sort our array.
- X*/
- Xvoid
- XSortItem()
- X{
- X qsort((char *)BaseItem, NumItem, sizeof *BaseItem, ItemCompare);
- X}
- X
- X
- X/*
- X** Use the bsearch() routine to find the item.
- X*/
- XITEM *
- XFindItem(Name)
- X char *Name;
- X{
- X ITEM *I;
- X ITEM Key;
- X
- X Key.Name = Name;
- X I = (ITEM *)bsearch((char *)&Key, (char *)BaseItem,
- X (unsigned int)NumItem, sizeof *BaseItem, ItemCompare);
- X return I;
- X}
- END_OF_FILE
- if test 6748 -ne `wc -c <'adt.c'`; then
- echo shar: \"'adt.c'\" unpacked with wrong size!
- fi
- # end of 'adt.c'
- fi
- if test -f 'codaserver.8' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'codaserver.8'\"
- else
- echo shar: Extracting \"'codaserver.8'\" \(5278 characters\)
- sed "s/^X//" >'codaserver.8' <<'END_OF_FILE'
- X.TH CODASERVER 8 LOCAL
- X.SH NAME
- Xcodaserver \- Code distribution aid daemon
- X.SH SYNOPSIS
- X.B codaserver
- X[
- X.B \-c
- X] [
- X.BI \-l file
- X] [
- X.BI \-r file
- X] [
- X.B \-t
- X]
- X.SH DESCRIPTION
- X.I Codaserver
- Xis the server for the code distribution system.
- XIt should be installed on any system where you want clients to be able
- Xto pick up files.
- X.PP
- X.I Codaserver
- Xis normally started as necessary by the inet daemon.
- XTo run it in an interactive test mode, use the ``\-t'' flag; this will
- Xread commands from standard input and echo results to standard output.
- XTo test the syntax of a codafile, use the ``\-r'' flag; this will read
- Xand parse the file, and report any errors to standard output.
- X.PP
- X.I Codaserver
- Xreports all transactions to a log file, normally
- X.IR /usr/spool/log/codalog .
- XTo specify a different log file, use the ``\-l'' flag; the name ``\-'' is
- Xtaken to mean standard output.
- XFor each in decoding the logs, every message is stamped with the process-id
- Xand a sequence number.
- X.PP
- XSee the
- X.I coda
- Xmanual page for a description of the
- X.I Codafile
- Xlanguage.
- X.PP
- XThe ``\-c'' flag prints out copyright and version information.
- X.SH PROTOCOL
- XThe coda server uses a simple protocol running over a TCP stream.
- XCommands and their responses are exchanged in ASCII, and lines are
- Xterminated by a carriage-return/news line pair.
- XIt is easy to debug the system by connecting to the server with a
- X.IR telnet (1)
- Xto the right port.
- X.SS "Message Types"
- X.PP
- XUpon first connecting, the server will send an acknowledgement; after
- Xthis the server will only reply to messages sent from the client.
- XEvery non-blank line sent to the server will result in one or more
- Xlines of reply that ultimately end with an
- X.I ACK
- Xor
- X.I NAK
- Xmessage.
- X.PP
- XAll messages from the server are preceded by a three-character code.
- XIf the fourth character is a space, the server has more data to
- Xsend (as in the
- X.I help
- Xcommand); if the fourth character is a dash, this line has the
- Xserver's final reply to the client's request.
- XThe following message types are sent by the server:
- X.TP
- X.I ACK
- X.br
- XThe last command successfully completed;
- Xthe rest of the line may contain some information.
- X.TP
- X.I NAK
- X.br
- Xthe rest of the line should give an explanation for the failure.
- X.TP
- X.I INF
- X.br
- XInformation line intended for the user (e.g., help output).
- X.TP
- X.I DAT
- X.br
- XData lines intended for client programs (e.g., file lists).
- XThe rest of the line is interpreted by the client program.
- XThere is currently one type of data line, it describes a file or
- Xdirectory to be loaded by the client.
- XAfter the four-character identifier are the four letters
- X.I ITEM
- Xand a space.
- XThe remainder of the line is a set of space-separated key-value
- Xpairs, where the key is a single letter followed by an equal
- Xsign.
- XThe values are all interpreted in a Unix context; numbers are sent
- Xin decimal.
- XThe current keys are:
- X.RS
- X.nf
- X W Type; \fId\fP for directory, \fIf\fP for file
- X N Name of the file as text
- X U The numeric id of the item's owner
- X G The numeric id of the item's group
- X M The decimal value of the item's permission bits
- X S The size of the item in bytes
- X T The modification date of the file
- X.fi
- X.RE
- X.SS "Server Commands"
- X.PP
- XCommands consist of a word, possibly followed by an argument.
- XThe command word may be in either case.
- XThe coda server understands the following commands:
- X.TP
- X.I "GOTO dir"
- X.br
- XThe argument is a directory for the server to
- X.IR chdir (2)
- Xto.
- XThis command is not as useful as it used to be.
- X.TP
- X.I "HELP"
- X.br
- XDescribe the available commands.
- X.TP
- X.I "HOST name"
- X.br
- XSet the name of the apparent destination host.
- XThis command is only available in test mode.
- XThe host name is converted to uppercase.
- X.TP
- X.I "LIST [block]"
- X.br
- XAfter a
- X.I read
- Xcommand, this will list walk through the directories listed in the
- XCodafile and send a set of data line listing all the files and
- Xdirectories that are applicable for the client system.
- XIf no block name is given, all applicable blocks in the file are walked.
- X.TP
- X.I "MESG [text]"
- X.br
- XThe text is written to the server's log file.
- X.TP
- X.I "QUIT"
- X.br
- XThe server exits.
- X.TP
- X.I "READ [file]"
- X.br
- XRead the indicated Codafile; the default is
- X.IR Codafile .
- XThis resets any root value that might have been previously set,
- Xand clears the item list.
- X.TP
- X.I "ROOT [path]"
- X.br
- XSet the root directory for relative pathnames.
- XThis can be used to override the root after a
- X.I read
- Xcommand has been given.
- XThe default path is
- X.IR / .
- X.TP
- X.I "SEND filename"
- X.br
- XAfter a
- X.I list
- Xcommand, this sends back an
- X.I ACK
- Xmessage, the uninterpreted bytes in the file, and a second
- X.I ACK
- Xmessage.
- XThe client must remember (from the
- X.I list
- Xcommand)
- Xhow big the file is so it knows how much data to expect.
- XOnly items mentioned in the most recent
- X.I list
- Xcommand can be sent.
- X.TP
- X.I "USER name pass"
- XLog in with the given name and password; only the
- X.I help
- Xand
- X.I mesg
- Xcommands can be used without logging in.
- X.SH AUTHOR
- XThis program was written by Rich $alz <rsalz@bbn.com>.
- XIt has the following copyright:
- X.RS
- X.nf
- XCopyright 1989 BBN Systems and Technologies Corporation.
- XAll Rights Reserved.
- XThis is free software, and may be distributed under the terms of the
- XGNU Public License; see the file COPYING for more details.
- X
- X$Header: codaserver.8,v 2.0 90/03/23 15:02:01 rsalz Exp $
- X.fi
- X.RE
- X.SH "SEE ALSO"
- Xcoda(1).
- END_OF_FILE
- if test 5278 -ne `wc -c <'codaserver.8'`; then
- echo shar: \"'codaserver.8'\" unpacked with wrong size!
- fi
- # end of 'codaserver.8'
- fi
- if test -f 'file.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'file.c'\"
- else
- echo shar: Extracting \"'file.c'\" \(8889 characters\)
- sed "s/^X//" >'file.c' <<'END_OF_FILE'
- X/*
- X** Copyright 1989 BBN Systems and Technologies Corporation.
- X** All Rights Reserved.
- X** This is free software, and may be distributed under the terms of the
- X** GNU Public License; see the file COPYING for more details.
- X**
- X** File routines for the CODA server.
- X*/
- X#include "server.h"
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#include <sys/dir.h>
- X#include <a.out.h>
- X#ifdef RCSID
- Xstatic char RCS[] =
- X "$Header: file.c,v 2.0 90/03/23 14:41:23 rsalz Exp $";
- X#endif /* RCSID */
- X
- XSTATIC int RootLen; /* Length of the root string */
- XSTATIC int ScanCount; /* How much have we looked at? */
- X
- X/*
- X** Yet another routine to walk through a directory tree. It is similar
- X** to ftw(3), but different. It is not based on licensed code.
- X*/
- XSTATIC int
- XFileWalk(Path, Predicate, Depth, UserData)
- X char *Path;
- X int (*Predicate)();
- X int Depth;
- X char *UserData;
- X{
- X register DIR *Dp;
- X register char *p;
- X register int i;
- X struct direct *E;
- X struct stat Sb;
- X long cookie;
- X char fullpath[MAXPATH];
- X
- X /* If we can't stat, pass it to the user but go no further. */
- X if (stat(Path, &Sb) < 0) {
- X (void)(*Predicate)(Path, (struct stat *)NULL, UserData);
- X return FW_NOFURTHER;
- X }
- X
- X /* Call the user's function. */
- X switch ((*Predicate)(Path, &Sb, UserData)) {
- X default:
- X case FW_NOFURTHER:
- X return FW_NOFURTHER;
- X case FW_EXIT:
- X return FW_EXIT;
- X case FW_PROCEED:
- X if ((Sb.st_mode & S_IFMT) != S_IFDIR)
- X return FW_PROCEED;
- X break;
- X }
- X
- X /* Open directory; and if we can't tell the user so. */
- X if ((Dp = opendir(Path)) == NULL)
- X return FW_NOFURTHER;
- X
- X /* For speed, remember where the last component starts. */
- X i = strlen(Path);
- X (void)strcpy(fullpath, Path);
- X p = &fullpath[i];
- X if (i && p[-1] != '/')
- X *p++ = '/';
- X
- X /* Read all entries in the directory. */
- X while (E = readdir(Dp)) {
- X if (EQ(E->d_name, ".") || EQ(E->d_name, ".."))
- X continue;
- X
- X /* If going too deep, remember our state and recycle. */
- X if (Depth <= 1) {
- X cookie = telldir(Dp);
- X (void)closedir(Dp);
- X Dp = NULL;
- X }
- X
- X /* Process the entry. */
- X (void)strcpy(p, E->d_name);
- X if (FileWalk(fullpath, Predicate, Depth - 1, UserData) == FW_EXIT) {
- X /* User's finished; clean up. */
- X if (Dp)
- X (void)closedir(Dp);
- X return FW_EXIT;
- X }
- X
- X /* Reopen the directory if necessary. */
- X if (Dp == NULL) {
- X if ((Dp = opendir(Path)) == NULL)
- X /* WTF? */
- X return FW_NOFURTHER;
- X seekdir(Dp, cookie);
- X }
- X }
- X
- X /* Clean up. */
- X (void)closedir(Dp);
- X return FW_PROCEED;
- X}
- X
- X
- X/*
- X** Do shell-style pattern matching for ?, \, [], and * characters.
- X** Might not be robust in face of malformed patterns; e.g., "foo[a-"
- X** could cause a segmentation violation.
- X**
- X** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
- X*/
- XSTATIC int
- XStar(s, p)
- X register char *s;
- X register char *p;
- X{
- X STATIC int Match();
- X
- X while (Match(s, p) == FALSE)
- X if (*++s == '\0')
- X return FALSE;
- X return TRUE;
- X}
- X
- XSTATIC int
- XMatch(s, p)
- X register char *s;
- X register char *p;
- X{
- X register int last;
- X register int matched;
- X register int reverse;
- X
- X for ( ; *p; s++, p++)
- X switch (*p) {
- X case '\\':
- X /* Literal match with following character. */
- X p++;
- X /* FALLTHROUGH */
- X default:
- X if (*s != *p)
- X return FALSE;
- X continue;
- X case '?':
- X /* Match anything. */
- X if (*s == '\0')
- X return FALSE;
- X continue;
- X case '*':
- X /* Trailing star matches everything. */
- X return *++p ? Star(s, p) : TRUE;
- X case '[':
- X /* [^....] means inverse character class. */
- X if (reverse = p[1] == '^')
- X p++;
- X for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
- X /* This next line requires a good C compiler. */
- X if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
- X matched = TRUE;
- X if (matched == reverse)
- X return FALSE;
- X continue;
- X }
- X
- X return *s == '\0';
- X}
- X
- X
- X/*
- X** Return TRUE if a file is an "a.out" file.
- X*/
- XSTATIC int
- XIsBinaryFile(Path)
- X char *Path;
- X{
- X FILE *F;
- X struct exec Head;
- X
- X if ((F = fopen(Path, "r")) == NULL
- X || fread((char *)&Head, sizeof Head, 1, F) != 1)
- X return FALSE;
- X (void)fclose(F);
- X switch (Head.a_magic) {
- X default:
- X return FALSE;
- X#ifdef OMAGIC
- X case OMAGIC:
- X return TRUE;
- X#endif /* OMAGIC */
- X#ifdef NMAGIC
- X case NMAGIC:
- X return TRUE;
- X#endif /* NMAGIC */
- X#ifdef ZMAGIC
- X case ZMAGIC:
- X return TRUE;
- X#endif /* ZMAGIC */
- X }
- X}
- X
- X
- X/*
- X** This is the predicate for the file walker. It gets passed the
- X** current EXCEPTION block, to see if the Path is something we want
- X** to add to our list or not.
- X*/
- XSTATIC int
- XAdder(Path, Sb, UserData)
- X char *Path;
- X struct stat *Sb;
- X char *UserData;
- X{
- X register EXCEPTION *E;
- X register STRLIST *S;
- X register char *tail;
- X
- X /* Silently skip bogus entries. */
- X if (Sb == NULL)
- X return FW_NOFURTHER;
- X
- X if (++ScanCount == SCAN_PING) {
- X Message("Still scanning...");
- X ScanCount = 0;
- X }
- X
- X /* Get last component. */
- X if (tail = strrchr(Path, '/'))
- X tail++;
- X else
- X tail = Path;
- X
- X switch (Sb->st_mode & S_IFMT) {
- X default:
- X /* Something we don't handle. */
- X return FW_PROCEED;
- X case S_IFDIR:
- X /* Look through all "directory" exceptions; if we find one for
- X * the client's host, go no further. */
- X for (E = (EXCEPTION *)UserData; E; E = E->Next)
- X if (E->Directory && HostIsInClass(TheHost, E->Class))
- X for (S = E->Value; S; S = S->Next) {
- X if (*S->Value == '^' && Match(Path, &S->Value[1]))
- X return FW_NOFURTHER;
- X if (*S->Value != '^' && Match(tail, S->Value))
- X return FW_NOFURTHER;
- X }
- X /* Make sure the user can hack on it. */
- X Sb->st_mode |= S_IREAD | S_IWRITE | S_IEXEC;
- X break;
- X case S_IFREG:
- X /* Normal file; if we don't want it, we still keep going. */
- X for (E = (EXCEPTION *)UserData; E; E = E->Next)
- X if (!E->Directory && HostIsInClass(TheHost, E->Class))
- X for (S = E->Value; S; S = S->Next) {
- X if (*S->Value == '^' && Match(Path, &S->Value[1]))
- X return FW_PROCEED;
- X if (*S->Value != '^' && Match(tail, S->Value))
- X return FW_PROCEED;
- X }
- X if (!AllowBinaries && IsBinaryFile(Path))
- X return FW_PROCEED;
- X break;
- X }
- X
- X /* Add the item, tell the Walker to keep going. */
- X if (strlen(Path) > RootLen
- X && Path[RootLen] == '/'
- X && strncmp(Path, TheRoot, RootLen) == 0)
- X Path += RootLen + 1;
- X AddItemToList(Path, Sb);
- X return FW_PROCEED;
- X}
- X
- X
- X/*
- X** Give status information on all the files in a block.
- X*/
- XSTATIC int
- XListFilesInBlock(B)
- X BLOCK *B;
- X{
- X register DIRLIST *D;
- X register char *p;
- X struct stat Sb;
- X char fullpath[MAXPATH];
- X
- X /* Does the host get this block? */
- X if (!HostIsInClass(TheHost, B->Class))
- X return FALSE;
- X
- X /* Loop over all directories in this block. */
- X for (ScanCount = 0, D = B->Directories; D; D = D->Next) {
- X /* Build the pathname. */
- X if (*D->Value == '/')
- X p = D->Value;
- X else {
- X (void)sprintf(fullpath, "%s/%s", TheRoot, D->Value);
- X p = fullpath;
- X }
- X if (!D->Directory)
- X (void)FileWalk(p, Adder, FASTDEPTH, (char *)D->Exceptions);
- X else if (stat(p, &Sb) >= 0)
- X /* Ignore exceptions? */
- X AddItemToList(D->Value, &Sb);
- X else
- X /* Silently skip bogus files. */
- X ;
- X }
- X
- X /* Done. */
- X return TRUE;
- X}
- X
- X
- X/*
- X** List all the files in the block.
- X*/
- Xvoid
- XListFiles(p)
- X char *p;
- X{
- X register BLOCK *B;
- X register ITEM *I;
- X register ITEM *Iend;
- X char buff[SIZE];
- X
- X ResetItem();
- X RootLen = strlen(TheRoot);
- X
- X if (*p) {
- X if ((B = FindBlock(p)) == NULL) {
- X Nack("No such block");
- X return;
- X }
- X if (!ListFilesInBlock(B)) {
- X Nack("Host doesn't get that block");
- X return;
- X }
- X }
- X else
- X /* List all blocks. */
- X for (B = BaseBlock.Next; B; B = B->Next)
- X if (!B->Excluded)
- X (void)ListFilesInBlock(B);
- X
- X SortItem();
- X for (I = BaseItem, Iend = &BaseItem[NumItem]; I < Iend; I++) {
- X (void)sprintf(buff, "ITEM W=%c N=%s U=%d G=%d M=%d S=%ld T=%ld",
- X I->Directory ? 'd' : 'f', I->Name, I->Uid,
- X I->Gid, I->Mode, (long)I->Size, (long)I->Time);
- X Data(buff);
- X }
- X
- X (void)sprintf(buff, "Found %d files", NumItem);
- X Ack(buff);
- X}
- X
- X
- X/*
- X** Send one file down the pipe.
- X*/
- Xvoid
- XSendFile(Name)
- X char *Name;
- X{
- X register FILE *F;
- X register int C;
- X ITEM *I;
- X char fullpath[MAXPATH];
- X
- X /* Can client get it? */
- X if ((I = FindItem(Name)) == NULL) {
- X Nack("File not found");
- X return;
- X }
- X
- X /* Open it, dealing with relative pathnames. */
- X if (Name[0] == '/')
- X F = fopen(Name, "r");
- X else {
- X (void)sprintf(fullpath, "%s/%s", TheRoot, Name);
- X F = fopen(fullpath, "r");
- X }
- X if (F == NULL) {
- X Nack((char *)NULL);
- X return;
- X }
- X
- X /* Send it. */
- X Ack(Name);
- X while ((C = getc(F)) != EOF)
- X (void)putchar(C);
- X (void)fclose(F);
- X#ifdef VERBOSE_LOG
- X LogSentItem(I);
- X#else
- X# ifdef lint
- X I = I;
- X# endif /* lint */
- X#endif /* VERBOSE_LOG */
- X Ack((char *)NULL);
- X}
- END_OF_FILE
- if test 8889 -ne `wc -c <'file.c'`; then
- echo shar: \"'file.c'\" unpacked with wrong size!
- fi
- # end of 'file.c'
- fi
- if test -f 'libvms.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'libvms.c'\"
- else
- echo shar: Extracting \"'libvms.c'\" \(7419 characters\)
- sed "s/^X//" >'libvms.c' <<'END_OF_FILE'
- X/*
- X** Copyright 1989 BBN Systems and Technologies Corporation.
- X** All Rights Reserved.
- X** This is free software, and may be distributed under the terms of the
- X** GNU Public License; see the file COPYING for more details.
- X**
- X** Client library routines for VMS with Wollongong 3.0 TCP.
- X** Check the "/INCLUDE" qualifier in descrip.mms.
- X**
- X** Our VMS documentation claims some functions exist that really don't,
- X** so we've had to implement them on our own.
- X**
- X** Also, Wollongong's header files try to re-specify some of the same
- X** same typedef's that the VMS C RTL specifies. Sigh.
- X*/
- X#include "client.h"
- X#include <types.h>
- X#include <string.h>
- X#include <ssdef.h>
- X#include <iodef.h>
- X#include <descrip.h>
- X#define time_t TWG_time_t
- X#define size_t TWG_size_t
- X#include "[sys]types2.h"
- X#include "[sys]socket.h"
- X#include "[netinet]in.h"
- X#undef time_t
- X#undef size_t
- X#ifdef RCSID
- Xstatic char RCS[] =
- X "$Header: libvms.c,v 2.0 90/04/09 16:29:34 rsalz Exp $";
- X#endif /* RCSID */
- X
- X
- X/*
- X** Depending on what version of the C RTL you have, you will need to
- X** edit these.
- X*/
- X#define NEED_UTIME
- X#undef NEED_RENAME
- X#undef NEED_MEMSET
- X
- XSTATIC int Channel; /* Something to talk with */
- X
- X
- X#ifdef NEED_UTIME
- X#include "vmsutime.inc"
- X#endif /* NEED_UTIME */
- X
- X
- X/*
- X** This comes from the AT&T public domain getopt handed out at 1985
- X** UNIFORUM and subsequently posted to Usenet.
- X*/
- Xint opterr = 1;
- Xint optind = 1;
- Xint optopt;
- Xchar *optarg;
- Xextern char *strchr();
- X
- Xint
- Xgetopt(ac, av, options)
- X int ac;
- X char **av;
- X char *options;
- X{
- X static int sp = 1;
- X REGISTER char *p;
- X
- X if (sp == 1) {
- X if (optind >= ac || av[optind][0] != '-' || av[optind][1] == '\0')
- X return EOF;
- X if (strcmp(av[optind], "--") == 0) {
- X optind++;
- X return EOF;
- X }
- X }
- X
- X optopt = av[optind][sp];
- X
- X /* Bogus flag? */
- X if (optopt == ':' || (p = strchr(options, optopt)) == NULL) {
- X if (opterr)
- X (void)fprintf(stderr, "%s: illegal option -- %c\n", av[0], optopt);
- X if (av[optind][++sp] == '\0') {
- X optind++;
- X sp = 1;
- X }
- X return '?';
- X }
- X
- X /* Flag needs an option? */
- X if (*++p == ':') {
- X if (av[optind][sp + 1])
- X optarg = &av[optind++][sp + 1];
- X else if (++optind < ac)
- X optarg = av[optind++];
- X else {
- X if (opterr)
- X (void)fprintf(stderr,
- X "%s: option requires an argument -- %c\n",
- X av[0], optopt);
- X sp = 1;
- X return '?';
- X }
- X sp = 1;
- X }
- X else {
- X if (av[optind][++sp] == '\0') {
- X sp = 1;
- X optind++;
- X }
- X optarg = NULL;
- X }
- X return optopt;
- X}
- X
- X
- X#ifdef NEED_MEMSET
- X/*
- X** Set memory to a value.
- X*/
- Xvoid *
- Xmemset(save, c, count)
- X void *save;
- X int c;
- X unsigned int count;
- X{
- X char *p;
- X register int i;
- X
- X if ((i = count) != 0)
- X for (p = save; --i >= 0; )
- X *p++ = c;
- X
- X return save;
- X}
- X#endif /* NEED_MEMSET */
- X
- X
- X#ifdef NEED_RENAME
- X/*
- X** Turn a nice pretty /unix/path/name into an ugly [.vms.path]name
- X*/
- XSTATIC void
- XVMSname(path, buffer)
- X char *path;
- X char *buffer;
- X{
- X REGISTER char *p;
- X REGISTER char *tail;
- X char temp[SIZE];
- X
- X /* Simple case "foo" ==> "foo" */
- X (void)strcpy(temp, path);
- X if ((tail = strrchr(temp, '/')) == NULL) {
- X strcpy(buffer, path);
- X return;
- X }
- X
- X /* Split off the last component. */
- X *tail++ = '\0';
- X
- X /* Turn all slashes into periods. */
- X for (p = temp; p = strchr(p, '/'); )
- X *p++ = '.';
- X if (temp[0] == '.')
- X (void)sprintf(buffer, "[%s]%s", &temp[1], tail);
- X else
- X (void)sprintf(buffer, "[.%s]%s", temp, tail);
- X}
- X
- X
- X/*
- X** Rename a file.
- X*/
- Xint
- Xrename(from, to)
- X char *from;
- X char *to;
- X{
- X struct dsc$descriptor_s Fdesc;
- X struct dsc$descriptor_s Tdesc;
- X char Fname[SIZE];
- X char Tname[SIZE];
- X
- X VMSname(from, Fname);
- X Fdesc.dsc$a_pointer = Fname;
- X Fdesc.dsc$w_length = strlen(Fname);
- X Fdesc.dsc$b_dtype = DSC$K_DTYPE_T;
- X Fdesc.dsc$b_class = DSC$K_CLASS_S;
- X
- X VMSname(to, Tname);
- X Tdesc.dsc$a_pointer = Tname;
- X Tdesc.dsc$w_length = strlen(Tname);
- X Tdesc.dsc$b_dtype = DSC$K_DTYPE_T;
- X Tdesc.dsc$b_class = DSC$K_CLASS_S;
- X
- X return lib$rename_file(&Fdesc, &Tdesc) == SS$_NORMAL ? 0 : -1;
- X}
- X#endif /* NEED_RENAME */
- X
- X
- X/*
- X** Remove a file.
- X*/
- Xint
- Xunlink(Name)
- X char *Name;
- X{
- X return delete(Name);
- X
- X}
- X
- X
- X/*
- X** Do the grundge work of getting us a socket.
- X*/
- XSTATIC int
- XGetSocket(machine, port)
- X char *machine;
- X int port;
- X{
- X unsigned long rhost();
- X REGISTER int s;
- X char *p;
- X struct sockaddr_in sin;
- X
- X /* Set up the socket. */
- X if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- X perror("Socket creation failed");
- X return -1;
- X }
- X
- X /* Set up the socket address. */
- X (void)memset((void *)&sin, '\0', sizeof sin);
- X p = machine;
- X if ((sin.sin_addr.s_addr = rhost(&p)) == -1) {
- X perror("No such machine");
- X return -1;
- X }
- X sin.sin_family = AF_INET;
- X sin.sin_port = htons(port);
- X
- X /* Connect to the server. */
- X if (connect(s, &sin, sizeof sin) < 0) {
- X perror("Connect failed");
- X netclose(s);
- X return -1;
- X }
- X
- X return s;
- X}
- X
- X
- X/*
- X** Open connection to server, return FALSE on error.
- X*/
- Xint
- XSRVopen(machine, port)
- X char *machine;
- X int port;
- X{
- X return (Channel = GetSocket(machine, port)) >= 0;
- X}
- X
- X
- X/*
- X** Send a QUIT and shut down.
- X*/
- Xvoid
- XSRVclose()
- X{
- X SRVput("QUIT");
- X (void)netclose(Channel);
- X}
- X
- X
- X/*
- X** Send a line to the server.
- X*/
- Xvoid
- XSRVput(p)
- X char *p;
- X{
- X if (SRVtrace)
- X (void)printf(">>>%s\n", p);
- X netwrite(Channel, p, strlen(p));
- X netwrite(Channel, "\r\n", 2);
- X}
- X
- X
- X/*
- X** Get a line of text from the server. Strip end-of-line characters.
- X*/
- Xint
- XSRVget(buff, size)
- X char *buff;
- X int size;
- X{
- X REGISTER char *p;
- X REGISTER char *bend;
- X REGISTER int c;
- X
- X for (bend = &buff[size - 1]; ; ) {
- X for (p = buff; ((c = SRVcget()) != '\n'); ) {
- X if (c == EOF)
- X return FALSE;
- X if (c != '\r' && p < bend)
- X *p++ = c;
- X }
- X *p = '\0';
- X if (SRVtrace)
- X (void)printf("<<<%s\n", buff);
- X if (strncmp(buff, "INF ", 4))
- X return TRUE;
- X (void)printf("Server message:\n\t%s\n", &buff[4]);
- X (void)fflush(stdout);
- X }
- X}
- X
- X
- X/*
- X** Get a character from the server.
- X*/
- Xint
- XSRVcget()
- X{
- X static char buff[1024];
- X static int count;
- X static int max;
- X
- X if (count == max) {
- X while ((max = netread(Channel, buff, sizeof buff)) == 0)
- X ;
- X if (max < 0)
- X return EOF;
- X if (max > sizeof buff)
- X (void)abort();
- X count = 0;
- X }
- X return buff[count++];
- X}
- X
- X
- X/*
- X** Get a password without echoing.
- X*/
- Xvoid
- XGetPassword(buff, size)
- X char *buff;
- X int size;
- X{
- X struct dsc$descriptor_s Desc;
- X int i;
- X int kb;
- X int mask;
- X int timeout;
- X int length;
- X
- X /* Create a keyboard to read from. */
- X if (smg$create_virtual_keyboard(&kb) != SS$_NORMAL) {
- X perror("Error creating virtual_keyboard");
- X exit(i);
- X }
- X
- X /* Set up the parameters. */
- X Desc.dsc$w_length = size;
- X Desc.dsc$b_dtype = DSC$K_DTYPE_T;
- X Desc.dsc$b_class = DSC$K_CLASS_S;
- X Desc.dsc$a_pointer = buff;
- X mask = IO$M_NOECHO;
- X timeout = 60;
- X length = 0;
- X
- X /* Read it. */
- X i = smg$read_string(&kb, &Desc, 0, &size, &mask, &timeout, 0, &length);
- X if (i != SS$_NORMAL) {
- X perror("Error reading password");
- X exit(i);
- X }
- X
- X /* Delete the keyboard. */
- X if (smg$delete_virtual_keyboard(&kb) != SS$_NORMAL) {
- X perror("Error deleting virtual keyboard");
- X exit(i);
- X }
- X
- X /* Clean up and return. */
- X (void)printf("\n");
- X buff[length] = '\0';
- X}
- END_OF_FILE
- if test 7419 -ne `wc -c <'libvms.c'`; then
- echo shar: \"'libvms.c'\" unpacked with wrong size!
- fi
- # end of 'libvms.c'
- fi
- if test -f 'server.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'server.c'\"
- else
- echo shar: Extracting \"'server.c'\" \(9605 characters\)
- sed "s/^X//" >'server.c' <<'END_OF_FILE'
- X/*
- X** Copyright 1989 BBN Systems and Technologies Corporation.
- X** All Rights Reserved.
- X** This is free software, and may be distributed under the terms of the
- X** GNU Public License; see the file COPYING for more details.
- X**
- X** Main driver for CODA server.
- X*/
- X#define MAINLINE
- X#include "server.h"
- X#include <pwd.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X#include <sys/stat.h>
- X#include <sys/socket.h>
- X#include <netinet/in.h>
- X#include <netdb.h>
- X#ifdef RCSID
- Xstatic char RCS[] =
- X "$Header: server.c,v 2.0 90/03/23 14:41:55 rsalz Exp $";
- X#endif /* RCSID */
- X
- X
- X/*
- X** A command has a text name, an internal value, and a help message.
- X*/
- Xtypedef struct _TABLE {
- X char *Name;
- X COMMAND Value;
- X char *Help;
- X} TABLE;
- X
- Xchar *LogFile = LOGFILE; /* Name of the log file */
- Xchar UnknownHost[] = GUESTHOST; /* For unknown hosts */
- X
- XSTATIC jmp_buf Context; /* When the bell rings */
- XSTATIC BOOL LoggedIn; /* Did we get a USER command? */
- XSTATIC BOOL Testing; /* Are we in test mode? */
- X
- XSTATIC TABLE Commands[] = { /* List of commands */
- X { "GOTO", CMDgoto, "Change to specified directory" },
- X { "EXIT", CMDquit, "Shut down server" },
- X { "HELP", CMDhelp, "Print this status report" },
- X { "HOST", CMDhost, "Specify name of destination host" },
- X { "MESG", CMDmesg, "Send message to log file" },
- X { "LIST", CMDlist, "List status of files [in block]" },
- X { "QUIT", CMDquit, "Shut down server" },
- X { "READ", CMDread, "Read control file, name optional" },
- X { "ROOT", CMDroot, "Set root for relative pathnames" },
- X { "SEND", CMDsend, "Start file-sending protocol" },
- X { "USER", CMDuser, "Log in a specified user" },
- X { "", CMD_time, NULL },
- X { NULL }
- X};
- X
- X
- X
- X/*
- X** Return a perror-style string.
- X*/
- Xchar *
- Xstrerror(e)
- X int e;
- X{
- X extern int sys_nerr;
- X extern char *sys_errlist[];
- X char buff[20];
- X
- X if (e < 0 || e > sys_nerr) {
- X (void)sprintf(buff, "Error code %d\n", e);
- X return buff;
- X }
- X return sys_errlist[e];
- X}
- X
- X
- X
- X/*
- X** Send a message saying a command was successful.
- X*/
- Xvoid
- XAck(p)
- X char *p;
- X{
- X (void)printf("ACK-%s\r\n", p ? p : "Done");
- X (void)fflush(stdout);
- X}
- X
- X
- X/*
- X** Send a message saying that a command failed.
- X*/
- Xvoid
- XNack(p)
- X char *p;
- X{
- X (void)printf("NAK-%s\r\n", p ? p : strerror(errno));
- X (void)fflush(stdout);
- X}
- X
- X
- X/*
- X** Send an information message. The client shoujld pass these on to
- X** the user.
- X*/
- Xvoid
- XMessage(p)
- X char *p;
- X{
- X (void)printf("INF %s\r\n", p ? p : "Never mind");
- X}
- X
- X
- X/*
- X** Send a data message. This is for the client program.
- X*/
- Xvoid
- XData(p)
- X char *p;
- X{
- X if (p)
- X (void)printf("DAT %s\r\n", p);
- X}
- X
- X
- X
- X/*
- X** When that bell rings, get out of here!
- X*/
- XSTATIC CATCHER
- XAlarmCatch()
- X{
- X longjmp(Context, 1);
- X /* NOTREACHED */
- X}
- X
- X
- X/*
- X** Read a line from the client. Quit if it times out. Otherwise
- X** parse the first word as a command, stuff the rest of the line as
- X** a possible argument to the command, and return the command's value.
- X*/
- XSTATIC COMMAND
- XReadLine(arg, size)
- X char *arg;
- X int size;
- X{
- X register char *p;
- X register char *q;
- X register TABLE *T;
- X char buff[SIZE];
- X
- X if (setjmp(Context) == 1)
- X return CMD_time;
- X
- X for ( ; ; ) {
- X /* Timed-out read. */
- X (void)alarm(TIMEOUT);
- X p = fgets(buff, sizeof buff, stdin);
- X (void)alarm(0);
- X if (p == NULL)
- X return CMDquit;
- X
- X /* Kill the terminator. */
- X if ((p = strchr(buff, '\r')) || (p = strchr(buff, '\n')))
- X *p = '\0';
- X
- X /* Skip whitespace, ignore totally blank lines. */
- X for (p = buff; *p && WHITE(*p); p++)
- X ;
- X if (*p == '\0')
- X continue;
- X
- X /* Find first word. */
- X for (q = p; *q && !WHITE(*q); q++)
- X ;
- X
- X /* Snip off first word, copy rest of line to argument. */
- X if (*q) {
- X for (*q = '\0'; *++q && WHITE(*q); )
- X ;
- X (void)strncpy(arg, q, size);
- X arg[size - 1] = '\0';
- X }
- X else
- X arg[0] = '\0';
- X Uppercase(p);
- X
- X /* Find first word in the command table. */
- X for (T = Commands; T->Name; T++)
- X if (EQ(T->Name, p))
- X return T->Value;
- X
- X Nack("Unknown command");
- X }
- X}
- X
- X
- X
- X
- X/*
- X** Get the name of the host where the client it.
- X*/
- XSTATIC void
- XGetClientHostname()
- X{
- X struct hostent *hp;
- X struct sockaddr_in venial;
- X char buff[SIZE];
- X int size;
- X
- X if (isatty(0))
- X /* Obviously a local call... */
- X TheHost = gethostname(buff, sizeof buff) < 0 ? NULL : buff;
- X else {
- X size = sizeof venial;
- X if (getpeername(0, (struct sockaddr *)&venial, &size) < 0)
- X TheHost = NULL;
- X else {
- X hp = gethostbyaddr((char *)&venial.sin_addr,
- X sizeof venial.sin_addr, AF_INET);
- X TheHost = hp ? hp->h_name : NULL;
- X }
- X }
- X
- X TheHost = TheHost ? COPY(TheHost) : COPY(UnknownHost);
- X Uppercase(TheHost);
- X}
- X
- X
- X/*
- X** Read a CODA control file to see if its valid.
- X*/
- XSTATIC void
- XCheckCodafile(p)
- X char *p;
- X{
- X ResetStorage();
- X if (!yyopen(TRUE, p)) {
- X Nack((char *)NULL);
- X exit(1);
- X }
- X if (yyparse() != BADPARSE && !HaveErrors)
- X exit(0);
- X Nack("Syntax errors found");
- X exit(1);
- X}
- X
- X
- X/*
- X** Verify a user's name and password.
- X*/
- XSTATIC void
- XLogin(p)
- X char *p;
- X{
- X static char BAD[] = "Bad username or password";
- X struct passwd *pwd;
- X char *pass;
- X char buff[SIZE];
- X
- X /* Split at the space into a name:password pair. */
- X if ((pass = strchr(p, ' ')) == NULL) {
- X Nack(BAD);
- X return;
- X }
- X *pass++ = '\0';
- X
- X /* Valid name with the right password? */
- X if ((pwd = getpwnam(p)) == NULL) {
- X Nack(BAD);
- X return;
- X }
- X if (!EQ(pwd->pw_passwd, crypt(pass, pwd->pw_passwd))) {
- X Nack(BAD);
- X return;
- X }
- X
- X /* Change identity. */
- X if (initgroups(p, pwd->pw_gid) < 0 || setuid(pwd->pw_uid) < 0) {
- X Nack((char *)NULL);
- X return;
- X }
- X
- X /* Done; log and acknowledge it. */
- X LoggedIn = TRUE;
- X (void)sprintf(buff, "Logged in %s", p);
- X LogText(buff);
- X Ack(buff);
- X}
- X
- X
- X/*
- X** Print a usage message and exit.
- X*/
- XSTATIC void
- XUsage()
- X{
- X (void)fprintf(stderr, "Usage: codaserver %s\n",
- X "[-c] [-lLogfile] [-rCodafile] [-t]");
- X exit(1);
- X}
- X
- X
- X/* ARGSUSED1 */
- Xmain(ac, av)
- X int ac;
- X char *av[];
- X{
- X static char LOGIN[] = "Login first";
- X register BOOL DidRead;
- X register char *p;
- X register COMMAND C;
- X register int i;
- X register TABLE *T;
- X char arg[SIZE];
- X
- X /* Parse JCL. */
- X while ((i = getopt(ac, av, "cl:r:t")) != EOF)
- X switch (i) {
- X default:
- X Usage();
- X /* NOTREACHED */
- X case 'c':
- X Copyright();
- X exit(0);
- X /* NOTREACHED */
- X case 'l':
- X LogFile = optarg;
- X break;
- X case 'r':
- X CheckCodafile(optarg);
- X /* NOTREACHED */
- X case 't':
- X /* Play it safe... */
- X if (isatty(0)) {
- X Testing = TRUE;
- X LoggedIn = TRUE;
- X (void)printf("Testing...\n");
- X }
- X break;
- X }
- X
- X /* Check for other arguments. */
- X ac -= optind;
- X av += optind;
- X if (ac)
- X Usage();
- X
- X if (!Testing) {
- X /* Set up IO descriptors, be robust in the face of varying inetd's. */
- X (void)close(1);
- X (void)close(2);
- X (void)dup(0);
- X (void)dup(0);
- X }
- X
- X /* Do various initializations. */
- X GetClientHostname();
- X (void)signal(SIGALRM, AlarmCatch);
- X ResetStorage();
- X LogOpen();
- X
- X /* Tell client we're here. */
- X (void)sprintf(arg, "Hello %s; how are you today?", TheHost);
- X Ack(arg);
- X
- X /* Read and dispatch loop. */
- X DidRead = FALSE;
- X while ((C = ReadLine(arg, sizeof arg)) != CMDquit)
- X switch (C) {
- X default:
- X Nack("Unimplemented command");
- X break;
- X
- X case CMDgoto:
- X if (!LoggedIn)
- X Nack(LOGIN);
- X else if (arg[0] == '\0')
- X Nack("Directory missing");
- X else if (chdir(arg) < 0)
- X Nack((char *)NULL);
- X else
- X Ack((char *)NULL);
- X break;
- X
- X case CMDhelp:
- X for (T = Commands; T->Name; T++)
- X if (T->Help) {
- X (void)sprintf(arg, "%s\t%s", T->Name, T->Help);
- X Message(arg);
- X }
- X Ack((char *)NULL);
- X break;
- X
- X case CMDhost:
- X if (!Testing)
- X Nack("I already know who you are");
- X else {
- X if (TheHost) {
- X free(TheHost);
- X TheHost = NULL;
- X }
- X Uppercase(arg);
- X if (HostWasDeclared(arg)) {
- X TheHost = COPY(arg);
- X Ack((char *)NULL);
- X }
- X else
- X Nack("Host undefined");
- X }
- X break;
- X
- X case CMDlist:
- X if (!LoggedIn)
- X Nack(LOGIN);
- X else if (TheHost == NULL)
- X Nack("No host specified");
- X else if (!DidRead)
- X Nack("Use READ first");
- X else
- X /* ListFiles() does its own Ack or Nack. */
- X ListFiles(arg);
- X break;
- X
- X case CMDmesg:
- X LogText(arg);
- X Ack((char *)NULL);
- X break;
- X
- X case CMDread:
- X if (!LoggedIn)
- X Nack(LOGIN);
- X else {
- X Rooted = FALSE;
- X AllowBinaries = TRUE;
- X ResetStorage();
- X DidRead = FALSE;
- X p = arg[0] ? arg : CONTROLFILE;
- X if (!yyopen(FALSE, p))
- X Nack((char *)NULL);
- X else {
- X if (yyparse() == BADPARSE || HaveErrors)
- X Nack("Can't parse file");
- X else {
- X LogReadfile(p);
- X if (!HostWasDeclared(TheHost)) {
- X (void)sprintf(arg, "Host \"%s\" not in the file.",
- X TheHost);
- X Message(arg);
- X }
- X Ack((char *)NULL);
- X DidRead = TRUE;
- X }
- X yyclose();
- X }
- X }
- X break;
- X
- X case CMDroot:
- X if (Rooted)
- X Nack("Permission denied");
- X else {
- X if (TheRoot)
- X free(TheRoot);
- X TheRoot = arg[0] ? COPY(arg) : NULL;
- X Ack((char *)NULL);
- X }
- X break;
- X
- X case CMDsend:
- X if (!LoggedIn)
- X Nack(LOGIN);
- X else if (!DidRead)
- X Nack("Use READ first");
- X else if (arg[0])
- X /* SendFile() does its own Ack or Nack. */
- X SendFile(arg);
- X else
- X Nack("Filename missing");
- X break;
- X
- X case CMDuser:
- X /* Login() does its own Ack or Nack. */
- X Login(arg);
- X break;
- X
- X case CMD_time:
- X LogClose("timeout");
- X exit(0);
- X /* NOTREACHED */
- X
- X }
- X
- X LogClose("quit");
- X exit(0);
- X /* NOTREACHED */
- X}
- END_OF_FILE
- if test 9605 -ne `wc -c <'server.c'`; then
- echo shar: \"'server.c'\" unpacked with wrong size!
- fi
- # end of 'server.c'
- fi
- if test -f 'server.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'server.h'\"
- else
- echo shar: Extracting \"'server.h'\" \(5418 characters\)
- sed "s/^X//" >'server.h' <<'END_OF_FILE'
- X/*
- X** Copyright 1989 BBN Systems and Technologies Corporation.
- X** All Rights Reserved.
- X** This is free software, and may be distributed under the terms of the
- X** GNU Public License; see the file COPYING for more details.
- X**
- X** Header file for CODA server.
- X** $Header: server.h,v 2.0 90/03/23 14:42:01 rsalz Exp $
- X*/
- X/* SUPPRESS 223 *//* Nested comment */
- X#include <stdio.h>
- X#include <sys/types.h>
- X
- X
- X/*
- X** Constants, compilation control, et cetera.
- X*/
- X
- X/* Assorted constants. */
- X#define TRUE 1 /* Any non-zero value */
- X#define FALSE 0 /* Must be zero */
- X#define BADPARSE 1 /* Returned by YACC; must be 1 */
- X#define SIZE 256 /* String buffer size */
- X#define MAXPATH 1024 /* Maximum pathname length */
- X#define HOST_DELTA 10 /* Clump for growing host array */
- X#define CLASS_DELTA 10 /* Clump for class arrays */
- X#define ITEM_DELTA 50 /* Clump for those other things */
- X#define SCAN_PING 200 /* How often to say we're alive */
- X#define FASTDEPTH 6 /* How far before closedir()? */
- X#define FW_NOFURTHER 1 /* FileWalker, go no further */
- X#define FW_PROCEED 2 /* FileWalker, keep going */
- X#define FW_EXIT 3 /* FileWalker, exit and pop up */
- X
- X/* Compile in RCS id strings? */
- X#ifndef SABER
- X#define RCSID
- X#endif /* SABER */
- X
- X/* Give up after this many seconds of inactivity. */
- X#define TIMEOUT (30 * 60)
- X
- X/* Default name of the log file. */
- X#define LOGFILE "/usr/spool/log/codalog"
- X
- X/* Default name of the file to read. */
- X#define CONTROLFILE "Codafile"
- X
- X/* Name of the built-in class that contains all hosts except UnknownHost. */
- X#define ALL "_ALL"
- X
- X/* Default name if host name isn't found. */
- X#define GUESTHOST "_ANYHOST"
- X
- X/* Return type of a signal-handling function. */
- Xtypedef int CATCHER; /* .. */
- X/* typedef void CATCHER; /* .. */
- X
- X/* Hide routines that can be hidden? */
- X#define STATIC static /* .. */
- X/*efine STATIC /* NULL */ /* .. */
- X
- X#define WHITE(c) ((c) == ' ' || (c) == '\t')
- X
- X/* Shut up, okay? */
- X#ifdef lint
- X#undef putc
- X#undef putchar
- X#undef ungetc
- X#undef RCSID
- X#endif /* lint */
- X
- X/* Memory allocation. */
- X#define NEW(T, c) \
- X ((T *)malloc((unsigned int)(sizeof (T) * (c))))
- X#define GROW(p, T, c) \
- X ((T *)realloc((char *)p, (unsigned int)(sizeof (T) * (c))))
- X#define COPY(p) \
- X strcpy(NEW(char, strlen(p) + 1), p)
- X
- X/* Fast front-end for string comparison. */
- X#define EQ(p, q) \
- X ((p) == (q) || ((p)[0] == (q)[0] && strcmp((p), (q)) == 0))
- X
- X
- X
- X/*
- X** List of server commands.
- X*/
- Xtypedef enum _COMMAND {
- X CMDgoto,
- X CMDhelp,
- X CMDhost,
- X CMDlist,
- X CMDmesg,
- X CMDquit,
- X CMDread,
- X CMDroot,
- X CMDsend,
- X CMDuser,
- X CMD_time
- X} COMMAND;
- X
- X
- X/*
- X** Is it, or is it not?
- X*/
- Xtypedef int BOOL;
- X
- X
- X/*
- X** A linked list of strings.
- X*/
- Xtypedef struct _STRLIST {
- X struct _STRLIST *Next;
- X char *Value;
- X} STRLIST;
- X
- X
- X/*
- X** An exception is a pattern for either files or a directory that is
- X** valid for a class of hosts.
- X*/
- Xtypedef struct _EXCEPTION {
- X struct _EXCEPTION *Next;
- X STRLIST *Value;
- X BOOL Directory;
- X char *Class;
- X} EXCEPTION;
- X
- X
- X/*
- X** A directory list is a linked list of pathnames and their exceptions.
- X*/
- Xtypedef struct _DIRLIST {
- X struct _DIRLIST *Next;
- X char *Value;
- X BOOL Directory;
- X EXCEPTION *Exceptions;
- X} DIRLIST;
- X
- X
- X/*
- X** A block has a name, whether it is part of the default list, a list of
- X** files, and a class that it is valid for.
- X*/
- Xtypedef struct _BLOCK {
- X struct _BLOCK *Next;
- X char *Name;
- X BOOL Excluded;
- X DIRLIST *Directories;
- X char *Class;
- X} BLOCK;
- X
- X
- X/*
- X** An item is something that can be sent to a client. It has permissions,
- X** a modification time, and might be a directory.
- X*/
- Xtypedef struct _ITEM {
- X char *Name;
- X int Uid;
- X int Gid;
- X BOOL Directory;
- X long Size;
- X time_t Time;
- X int Mode;
- X} ITEM;
- X
- X
- X/*
- X** Data is declared everywhere, lives oncewhere.
- X*/
- X#ifdef MAINLINE
- X#define EXTERN /* NULL */
- X#else
- X#define EXTERN extern
- X#endif /* MAINLINE */
- X
- XEXTERN BLOCK BaseBlock; /* Chain of known blocks */
- XEXTERN BOOL AllowBinaries; /* Don't check for a.out files? */
- XEXTERN BOOL Rooted; /* Can client set the root? */
- Xextern char UnknownHost[]; /* Name of the unknown host */
- Xextern char *LogFile; /* Name of the log file */
- XEXTERN char *TheHost; /* Host that called us */
- XEXTERN char *TheRoot; /* Root for relative pathnames */
- XEXTERN int HaveErrors; /* Failed to parse Codafile? */
- XEXTERN ITEM *BaseItem; /* Array of things to send */
- XEXTERN int NumItem; /* Size of said array */
- X
- X/* Our routines. */
- XBLOCK *FindBlock();
- XITEM *FindItem();
- Xchar *strerror();
- Xint HostIsInClass();
- Xint yyopen();
- Xint yyparse();
- Xvoid Ack();
- Xvoid AddClassesToClass();
- Xvoid AddHostToClass();
- Xvoid AddItemToList();
- Xvoid Data();
- Xvoid DefineBlock();
- Xvoid DefineHost();
- Xvoid ListFiles();
- Xvoid LogClose();
- Xvoid LogOpen();
- Xvoid LogReadfile();
- Xvoid LogSentItem();
- Xvoid LogText();
- Xvoid Message();
- Xvoid Nack();
- Xvoid ResetItem();
- Xvoid ResetStorage();
- Xvoid SendFile();
- Xvoid SortItem();
- Xvoid Uppercase();
- Xvoid yyclose();
- Xvoid yyerror();
- X
- X/* From the C library. */
- Xextern int errno;
- Xextern int optind;
- Xextern time_t time();
- Xextern char *optarg;
- Xextern char *bsearch();
- Xextern char *crypt();
- Xextern char *getwd();
- Xextern char *malloc();
- Xextern char *realloc();
- Xextern char *sprintf(); /* Too painful, my ass */
- Xextern char *strcat();
- Xextern char *strchr();
- Xextern char *strcpy();
- Xextern char *strncpy();
- Xextern char *strrchr();
- END_OF_FILE
- if test 5418 -ne `wc -c <'server.h'`; then
- echo shar: \"'server.h'\" unpacked with wrong size!
- fi
- # end of 'server.h'
- fi
- echo shar: End of archive 2 \(of 3\).
- cp /dev/null ark2isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- exit 0 # Just in case...
-